#include "SQLInsertStatement.h"

#include "../SQLExpr.h"
#include "../../../utils/instanceof.h"
#include "../../SQLUtils.h"
#include "../../../utils/listAddAll.h"
#include "../../../utils/listTran.h"
#include "../../visitor/SQLASTVisitor.h"
#include "SQLWithSubqueryClause.h"

SQLExpr_list_ptr SQLInsertStatement_ValuesClause::emptyListSQLExpr = std::make_shared<std::list<SQLExpr_ptr>>();

SQLInsertStatement_ValuesClause::SQLInsertStatement_ValuesClause()
    : SQLInsertStatement_ValuesClause(SQLInsertStatement_ValuesClause::emptyListSQLExpr)
{
}

SQLObject_ptr SQLInsertStatement_ValuesClause::clone()
{
  SQLExpr_list_ptr tmp = std::make_shared<std::list<SQLExpr_ptr>>();
  SQLObject_ptr clone_tmp = SQLInsertStatement_ValuesClause_ptr(new SQLInsertStatement_ValuesClause(tmp));
  SQLInsertStatement_ValuesClause_ptr x = std::dynamic_pointer_cast<SQLInsertStatement_ValuesClause>(clone_tmp);
  // SQLInsertStatement_ValuesClause *x = new SQLInsertStatement_ValuesClause(tmp);
  for (Object_ptr v : *values)
  {
    x->addValue(v);
  }
  return x;
}

BOOL_ptr SQLInsertStatement_ValuesClause::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  auto it_values = values->begin();
  for (int i = 0; i < values->size(); i++)
  {
    std::advance(it_values, i);
    if ((*it_values) == expr)
    {
      target->setParent(SharedObject(SQLInsertStatement_ValuesClause));
      (*it_values) = target;
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

SQLInsertStatement_ValuesClause::SQLInsertStatement_ValuesClause(SQLExpr_list_ptr values)
{
  // SQLExpr_list_ptr  values;
  this->values = values;
  auto it_values = values->begin();
  for (int i = 0; i < values->size(); ++i)
  {
    std::advance(it_values, i);
    (*it_values)->setParent(SharedObject(SQLInsertStatement_ValuesClause));
  }
}

SQLInsertStatement_ValuesClause::SQLInsertStatement_ValuesClause(SQLExpr_list_ptr values, SQLObject_ptr parent)
{
  this->values = values;
  auto it_values = values->begin();
  for (int i = 0; i < values->size(); ++i)
  {
    std::advance(it_values, i);
    auto val = (*it_values);
    if (instanceof <SQLExpr, SQLObject>(val))
    {
      (std::dynamic_pointer_cast<SQLObject>(val))->setParent(SharedObject(SQLInsertStatement_ValuesClause));
    }
  }
  this->parent = parent;
}

void SQLInsertStatement_ValuesClause::addValue(Object_ptr value)
{
  if (instanceof <Object, SQLObject>(value))
  {
    (std::dynamic_pointer_cast<SQLObject>(value))->setParent(SharedObject(SQLInsertStatement_ValuesClause));
  }
  values->push_back(std::dynamic_pointer_cast<SQLExpr>(value));
}

void SQLInsertStatement_ValuesClause::addValue(SQLExpr_ptr value)
{
  value->setParent(SharedObject(SQLInsertStatement_ValuesClause));
  values->push_back(value);
}

SQLExpr_list_ptr SQLInsertStatement_ValuesClause::getValues()
{
  return values;
}

void SQLInsertStatement_ValuesClause::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLInsertStatement_ValuesClause)))
  {
    auto it_values = values->begin();
    for (int i = 0; i < values->size(); i++)
    {
      std::advance(it_values, i);
      SQLExpr_ptr item = (*it_values);
      if (instanceof <SQLExpr, SQLObject>(item))
      {
        SQLObject_ptr value = std::dynamic_pointer_cast<SQLObject>(item);
        value->accept(visitor);
      }
    }
  }

  visitor->endVisit(SharedObject(SQLInsertStatement_ValuesClause));
}

string_ptr SQLInsertStatement_ValuesClause::getOriginalString()
{
  return originalString;
}

void SQLInsertStatement_ValuesClause::setOriginalString(string_ptr originalString)
{
  this->originalString = originalString;
}

int SQLInsertStatement_ValuesClause::getReplaceCount()
{
  return replaceCount;
}

void SQLInsertStatement_ValuesClause::incrementReplaceCount()
{
  this->replaceCount++;
}

SQLInsertStatement::SQLInsertStatement()
{
}

void SQLInsertStatement::cloneTo(SQLInsertStatement_ptr x)
{
  SQLInsertInto::cloneTo(x);
  x->dbType = dbType;
  x->upsert = upsert;
  x->afterSemi = afterSemi;

  if (with != NULL)
  {
    x->setWith(std::dynamic_pointer_cast<SQLWithSubqueryClause>(with->clone()));
  }
}

SQLObject_ptr SQLInsertStatement::clone()
{
  SQLObject_ptr clone_tmp = SQLInsertStatement_ptr(new SQLInsertStatement());
  SQLInsertStatement_ptr x = std::dynamic_pointer_cast<SQLInsertStatement>(clone_tmp);
  // SQLInsertStatement *x = new SQLInsertStatement();
  cloneTo(x);
  return x;
}

void SQLInsertStatement::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLInsertStatement)))
  {
    this->acceptChild(visitor, tableSource);
    SQLObject_list_ptr tmp_columns = ListTran::tran_class<SQLExpr, SQLObject>(columns);
    this->acceptChild(visitor, tmp_columns);
    SQLObject_list_ptr tmp_valuesList = ListTran::tran_class<SQLInsertStatement_ValuesClause, SQLObject>(SQLInsertInto::valuesList);
    this->acceptChild(visitor, tmp_valuesList);
    this->acceptChild(visitor, query);
  }

  visitor->endVisit(SharedObject(SQLInsertStatement));
}

SQLObject_list_ptr SQLInsertStatement::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();

  children->push_back(std::dynamic_pointer_cast<SQLObject>(tableSource));
  Utils::ListAddAll<SQLExpr, SQLObject>(this->columns, children);
  Utils::ListAddAll<SQLInsertStatement_ValuesClause, SQLObject>(SQLInsertInto::valuesList, children);
  if (query != NULL)
  {
    children->push_back(query);
  }

  return children;
}

BOOL_ptr SQLInsertStatement::isUpsert()
{
  return upsert;
}

void SQLInsertStatement::setUpsert(BOOL_ptr upsert)
{
  this->upsert = upsert;
}

DbType_ptr SQLInsertStatement::getDbType()
{
  return dbType;
}

void SQLInsertStatement::setDbType(DbType_ptr dbType)
{
  if (dbType != nullptr)
  {
    this->dbType = dbType;
  }
}

BOOL_ptr SQLInsertStatement::isAfterSemi()
{
  return afterSemi;
}

void SQLInsertStatement::setAfterSemi(BOOL_ptr afterSemi)
{
  this->afterSemi = afterSemi;
}

SQLWithSubqueryClause_ptr SQLInsertStatement::getWith()
{
  return with;
}

void SQLInsertStatement::setWith(SQLWithSubqueryClause_ptr with)
{
  if (with != NULL)
  {
    with->setParent(SharedObject(SQLInsertStatement));
  }
  this->with = with;
}

string_ptr SQLInsertStatement::toString()
{
  string_ptr tmp = SQLUtils::toSQLString(std::dynamic_pointer_cast<SQLObject>(SharedObject(SQLInsertStatement)), dbType);
  return (tmp);
}
